package com.xixing.weixin.utils;


import com.xixing.weixin.domain.Account;
import com.xixing.weixin.exception.AccountException;
import com.xixing.weixin.exception.ArgumentException;
import com.xixing.weixin.exception.WeixinExecuteException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.htmlparser.Node;
import org.htmlparser.Parser;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.TableColumn;
import org.htmlparser.tags.TableRow;
import org.htmlparser.tags.TableTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.util.SimpleNodeIterator;

import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.*;

public class GzhuSchoolUtils {
    public static final String loginUrl = "https://cas.gzhu.edu.cn/cas_server/login";
    public static final String serviceUrl = "https://cas.gzhu.edu.cn/cas_server/login?service=http%3a%2f%2f202.192.18.183%2fLogin_gzdx.aspx%3frequesturl%3dcontent_gzdx.aspx";
    public static final String SCORE_URL = "http://202.192.18.183/xscj_gc.aspx?xh={0}&zgh={0}";
    public static final String COURSE_URL = "http://202.192.18.183/xskbcx.aspx?xh={0}&zgh={0}";
    public static final String GB2312 = "GB2312";

    private static ResourceBundle resourceBundle = ResourceBundle.getBundle("template");

    private static String VIEW_STAT_START = "<input type=\"hidden\" name=\"__VIEWSTATE\" value=\"";
    private static String VIEW_STAT_END = "\"";

    private static Map<String, DefaultHttpClient> userHttpClients = new HashMap<String, DefaultHttpClient>();
    private static final int[] cols = new int[]{3, 6, 7, 8};

    public static void main(String[] args) throws Exception {


    }


    /**
     * 取得课程表.
     *
     * @param username 用户
     * @param password 密码
     * @return 课程表
     */
    public static String findCourse(String username, String password) throws IOException, AccountException {
        HttpClient httpClient = getHttpsClient(username);

        login(httpClient, username, password);

        // 访问课程.
        String url = MessageFormat.format(COURSE_URL, username);
        return HttpClientUtils.get(httpClient, url);
    }

    /**
     * 取得课程表.
     *
     * @param username 用户
     * @param password 密码
     * @param year     学年(比如：2011-2012)
     * @param term     学期(比如：2)
     * @return 课程表
     */
    public static String findCourse(String username, String password, String year, String term) throws IOException, AccountException {
        HttpClient httpClient = getHttpsClient(username);

        login(httpClient, username, password);

        // 访问课程.
        String url = MessageFormat.format(COURSE_URL, username);

        String html = HttpClientUtils.get(httpClient, url);
        String viewStat = HtmlParseUtils.findViewState(html);

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new BasicNameValuePair("__EVENTTARGET", "xnd"));
        params.add(new BasicNameValuePair("__EVENTARGUMENT", ""));
        params.add(new BasicNameValuePair("xnd", year));
        params.add(new BasicNameValuePair("xqd", term));
        params.add(new BasicNameValuePair("__VIEWSTATE", viewStat));
        return HttpClientUtils.post(httpClient, url, params, Charset.forName("GB2312"));
    }

    /**
     * 查询所学所有成绩.
     *
     * @param username 用户名.
     * @param password 密码.
     * @return 成绩HTML.
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     * @throws IOException
     */
    public static String findScore(String username, String password) throws IOException, AccountException {
        String button2 = "Button2";
        return findScore(username, password, "", button2);
    }

    /**
     * 按学年查询成绩.
     *
     * @param username  用户名.
     * @param password  密码.
     * @param scoreYear 学年.
     * @return 成绩HTML.
     */
    public static String findScore(String username, String password, String scoreYear) throws IOException, AccountException {
        String button5 = "Button5";
        return findScore(username, password, scoreYear, button5);
    }


    private static String findScore(String username, String password, String scoreYear, String button) throws IOException, AccountException {
        HttpClient httpClient = getHttpsClient(username);

        login(httpClient, username, password);


        // 访问成绩.
        String scoreUrl = MessageFormat.format(SCORE_URL, username);

        String html = HttpClientUtils.get(httpClient, scoreUrl);
        String viewStat = HtmlParseUtils.findViewState(html);


        List<NameValuePair> scoreParams = new ArrayList<NameValuePair>();
        scoreParams.add(new BasicNameValuePair("ddlXN", scoreYear));
        scoreParams.add(new BasicNameValuePair(button, ""));
        scoreParams.add(new BasicNameValuePair("__VIEWSTATE", viewStat));

        return HttpClientUtils.post(httpClient, scoreUrl, scoreParams, Charset.forName("GB2312"));

    }

    /**
     * 是否为合法的用户.
     *
     * @param username 用户名.
     * @param password 密码.
     * @return 用户信息是否合法.
     */
    public static boolean validUser(String username, String password) {
        try {
            HttpClient httpClient = getHttpsClient(username);
            return loginSSO(httpClient, username, password);
        } catch (Exception e) {
            return false;
        }

    }

    private static boolean loginSuccess(String html) {
        return !html.contains("<title>统一身份认证平台</title>");
    }

    private static void login(HttpClient httpClient, String username, String password) throws IOException, AccountException {

        boolean success = loginSSO(httpClient, username, password);
        if (!success)
            throw new AccountException(Account.GZHU_SCHOOL);

        // 访问服务.
        HttpClientUtils.getSilent(httpClient, serviceUrl);
    }

    private static boolean loginSSO(HttpClient httpClient, String username, String password) throws IOException {
        HttpClientUtils.getSilent(httpClient, loginUrl);

        // 登陆.
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("username", username));
        nvps.add(new BasicNameValuePair("password", password));
        nvps.add(new BasicNameValuePair("_eventId", "submit"));
        nvps.add(new BasicNameValuePair("lt", "e1s1"));
        nvps.add(new BasicNameValuePair("imageField.x", "41"));
        nvps.add(new BasicNameValuePair("imageField.y", "7"));
        String html = HttpClientUtils.post(httpClient, loginUrl, nvps);
        return loginSuccess(html);
    }


    private static HttpClient getHttpsClient(String username) {

        DefaultHttpClient httpClient = userHttpClients.get(username);
        if (httpClient != null) {
            return httpClient;
        }

        httpClient = HttpClientUtils.createHttpsClient();
        userHttpClients.put(username, httpClient);
        return httpClient;
    }

    public static String parseScore(String html) throws ParserException {
        StringBuffer buffer = new StringBuffer();
        Parser parser = Parser.createParser(html, "GB2312");
        NodeList nodes = parser.extractAllNodesThatMatch(new HasAttributeFilter("id", "Datagrid1"));
        TableTag table = (TableTag) nodes.elementAt(0);

        String stuname = parseName(html);    //获取名字
        String semester = parseYear(html);    //获取学年


        //取得表中的行集
        TableRow[] rows = table.getRows();

        String[] titles = new String[cols.length];
        {
            TableRow tr = rows[0];
            TableColumn[] td = tr.getColumns();
            for (int i = 0; i < cols.length; i++) {
                titles[i] = td[cols[i]].toPlainTextString();
            }
        }

        int count = rows.length - 1;
        //  "你好,{0},{1}年,一共{2}科.\n"
        buffer.append(MessageFormat.format(resourceBundle.getString("SCORE_TITLE"), stuname, semester, count));


        //遍历每行
        for (int r = 1; r < rows.length; r++) {
            TableRow tr = rows[r];
            TableColumn[] td = tr.getColumns();
            for (int i = 0; i < cols.length; i++) {
                buffer.append(r + ".").append(titles[i]).append(":").append(td[cols[i]].toPlainTextString()).append(" ");
            }
            buffer.append("\n");
        }
        //去掉课程名称字段
        String result = buffer.toString().replace("课程名称:", "");
        return result;
    }

    private static String parseYear(String html) throws ParserException {
        //获取学年
        String semester = "";
        Parser parser2 = Parser.createParser(html, "GB2312");
        NodeList nodes2 = parser2.extractAllNodesThatMatch(new AndFilter(new TagNameFilter("option"), new HasAttributeFilter("selected", "selected")));
        if (nodes2 != null) {
            for (int i = 0; i < nodes2.size(); i++) {
                Node textnode = (Node) nodes2.elementAt(i);
                NodeList children = textnode.getChildren();
                Node node = children.elementAt(0);
                String text = node.getText();
                //判断是否是学年格式 "20xx-20xx"
                String[] split = text.split("-");
                if (split.length > 0) {
                    semester = text;
                }
            }
        }
        return semester;
    }

    //获取名字.
    private static String parseName(String html) throws ParserException {
        String text = HtmlParseUtils.findById(html, GB2312, "Label5");
        return text.split("：")[1];
    }

    public static String parsePga(String html) throws ParserException {
        StringBuffer buffer = new StringBuffer();
        String stuname = parseName(html);    //获取名字
        String semester = null;
        try {
            semester = parseYear(html);    //获取学年
            buffer.append(MessageFormat.format(resourceBundle.getString("PGA_TITLE"), stuname, semester));
        } catch (NullPointerException e) {
            buffer.append(MessageFormat.format(resourceBundle.getString("PGA_TITLE2"), stuname));
        }
        Parser parser = Parser.createParser(html, "GB2312");
        NodeList nodes = parser.extractAllNodesThatMatch(new OrFilter(new HasAttributeFilter("id", "pjxfjd"), new HasAttributeFilter("id", "xfjdzh")));
        SimpleNodeIterator elements = nodes.elements();
        while (elements.hasMoreNodes()) {
            Node node = elements.nextNode();
            buffer.append(node.toPlainTextString()).append(" ");
        }
        return buffer.toString();
    }

    public static String parseCourse(String html) throws ParserException {
        StringBuffer buffer = new StringBuffer();
        Parser parser = Parser.createParser(html, "GB2312");
        NodeList nodes = parser.extractAllNodesThatMatch(new HasAttributeFilter("id", "Table1"));
        TableTag table = (TableTag) nodes.elementAt(0);
        //取得表中的行集
        TableRow[] rows = table.getRows();


        //遍历每行
        for (int r = 1; r < rows.length; r++) {
            TableRow tr = rows[r];
            TableColumn[] td = tr.getColumns();
            for (int i = 1; i < td.length; i++) {
                if (i == 1) {
                    if (!"2".equals(td[0].getAttribute("colspan"))) {
                        continue;
                    }
                }
                String text = td[i].toPlainTextString().replaceAll("&nbsp;", " ");
                if (StringUtils.isNotBlank(text)) {
                    buffer.append(text).append("; ");
                }
            }
            buffer.append("\n");
        }

        return buffer.toString();
    }

    //根据星期返回课程表
    public static String parseCourseByWeedDay(String html, String weekday) throws ParserException, WeixinExecuteException {
        StringBuffer buffer = new StringBuffer();

        weekday = convertWeekDay(weekday);
        String regex = resourceBundle.getString("WEEK") + weekday;//weekday
        Parser parser = Parser.createParser(html, "GB2312");
        NodeList nodes = parser.extractAllNodesThatMatch(new HasAttributeFilter("id", "Table1"));
        TableTag table = (TableTag) nodes.elementAt(0);
        //取得表中的行集
        TableRow[] rows = table.getRows();

        //标题头
        buffer.append(regex).append(":\n");

        //遍历每行
        for (int r = 1; r < rows.length; r++) {
            TableRow tr = rows[r];
            TableColumn[] td = tr.getColumns();
            for (int i = 1; i < td.length; i++) {
                if (i == 1) {
                    if (!"2".equals(td[0].getAttribute("colspan"))) {
                        continue;
                    }
                }
                String text = td[i].toPlainTextString().replaceAll("&nbsp;", "");
                if (StringUtils.isNotBlank(text)) {
                    if (text.contains(regex)) {
                        //显示格式
                        String resultRegex = "}";
                        String[] value = text.split(regex);
                        String course = value[0] + "\n";
                        String classz = value[1].split(resultRegex)[0] + resultRegex + "\n";
                        String teacher = value[1].split(resultRegex)[1];
                        //组合
                        String result = course + classz + teacher;
                        buffer.append(result).append("\n \n");
                    }
                }
            }
        }

        //没课的情况
        String s = buffer.toString();
        String[] split = s.split(regex+":\n");
        if (split.length == 0) {  //课程为空
            buffer.append(resourceBundle.getString("COURSE_PROMPT"));

        }
        return buffer.toString();
    }

    //周数转换
    private static String convertWeekDay(String weekday) throws WeixinExecuteException {
        Calendar cal = Calendar.getInstance();
        int calWeekday = cal.get(Calendar.DAY_OF_WEEK);
        if (weekday == null) {
            weekday = String.valueOf(calWeekday == 1 ? 7 : (calWeekday - 1));
        }

        if (weekday.equals("1")) {
            weekday = resourceBundle.getString("WEEK1");
        } else if (weekday.equals("2")) {
            weekday = resourceBundle.getString("WEEK2");
        } else if (weekday.equals("3")) {
            weekday = resourceBundle.getString("WEEK3");
        } else if (weekday.equals("4")) {
            weekday = resourceBundle.getString("WEEK4");
        } else if (weekday.equals("5")) {
            weekday = resourceBundle.getString("WEEK5");
        } else if (weekday.equals("6")) {
            weekday = resourceBundle.getString("WEEK6");
        } else if (weekday.equals("7")) {
            weekday = resourceBundle.getString("WEEK7");
        } else {
            throw new ArgumentException();
        }
        return weekday;

    }
}

